怎么阻止栈溢出被利用
这个可以从根源上解决,就是解决栈溢出,解决栈溢出可以用栈把递归转换成非递归,还可以使用static对象替代nonstatic局部对象。最后可以增大堆栈大小值,从这三个方面入手来解决栈溢出就可以防止栈溢出被利用了
针对栈溢出攻击的预防措施有以下这些:
地址空间随机化:顾名思义,程序每次加载到的内存位置是随机的,所以,即使可以利用栈溢出控制函数的返回地址,但是无法确定恶意代码的位置,因此,可以有效地防范栈溢出攻击。
不可执行栈:不可执行栈的基本原理是将数据所在的内存页标记为不可执行的,当进程尝试去执行数据页面上的指令时,CPU就会抛出异常,而不是去执行。所以,当开启了不可执行栈选项时,即使我们的恶意代码已经插入到内存,但由于处在数据页面,因此无法执行从而实现防御攻击。
Stack Guard:具体是再缓冲区(如:栈)和控制信息(如 ebp等)间插入一个canary word。这样,当缓冲区溢出时,再返回地址被覆盖之前canary word会首先被覆盖,通过检测canary word的值是否被修改,就可以判断是否发生了溢出,如果出现溢出则进行终止溢出的进程来进行防御。
使用模糊识别检测:由于溢出类漏洞的填充数据对于攻击本身是没有意义的,即只是用来占位以达到数据长度的目的,这部分一般会被攻击者以习惯模式填充(如多个字符重复多遍),而这部分数据在正常访问情况下,是外部输入中有意义的部分。另外输入的shellcode和跳转地址部分与正常的输入一般情况下也有差别,基于这些差别可以建立起来模糊识别的模型,用于检测对未知漏洞的攻击。
使用基于虚拟技术的检测技术:对于安全性要求很高、需要重点防护的系统,基于漏洞特征与攻击特征的防御难免还有漏网之鱼。就像Honey Pot系统可以用真实的系统做诱饵也可以虚拟一个诱饵系统一样,防御设备也可以虚拟一个跟真实系统相近的系统,用于检测对系统的访问是否存在攻击。
由于栈一般默觉得1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。
解决方式:
方法一:用栈把递归转换成非递归
通常,一个函数在调用还有一个函数之前,要作例如以下的事情:
a)将实在參数,返回地址等信息传递给被调用函数保存;
b)为被调用函数的局部变量分配存储区;
c)将控制转移到被调函数的入口.
从被调用函数返回调用函数之前,也要做三件事情:
a)保存被调函数的计算结果;
b)释放被调函数的数据区;
c)按照被调函数保存的返回地址将控制转移到调用函数.
全部的这些,不论是变量还是地址,本质上来说都是”数据”,都是保存在系统所分配的栈中的. 那么自己就能够写一个栈来存储必要的数据,以降低系统负担。
方法二:使用static对象替代nonstatic局部对象
在递归函数设计中,能够使用static对象替代nonstatic局部对象(即栈对象),这不仅能够降低每次递归调用和返回时产生和释放nonstatic对象的开销,并且static对象还能够保存递归调用的中间状态,并且可为各个调用层所訪问。
方法三:增大堆栈大小值
当创建一个线程的堆栈时,系统将会保留一个链接程序的/STACK开关指明的地址空间区域。可是,当调用CreateThread或_beginthreadex函数时,能够重载原先提交的内存数量。这两个函数都有一个參数,能够用来重载原先提交给堆栈的地址空间的内存数量。假设设定这个參数为0,那么系统将使用/STACK开关指明的已提交的堆栈大小值。后面将假定我们使用默认的堆栈大小值,即1MB的保留区域,每次提交一个页面的内存。